package cn.quevo.core.file;

import cn.quevo.core.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 文件压缩打包
 *
 * @author July july_sky@foxmail.com
 * @version 1.0
 * @date 2017年8月24日 下午5:17:18
 * @Copyright ©2015-2035 湘豫(北京)科技有限公司. All Rights Reserved.
 */
public class ZipCompressing {

    private final static Logger log = LoggerFactory.getLogger(ZipCompressing.class);

    /**
     * 压缩ZIP
     *
     * @param zipFileName
     * @param inputFile
     * @throws Exception
     * @author July july_sky@foxmail.com
     * @date 2017年8月24日 下午5:23:19
     */
    public static void zip(String zipFileName, File inputFile) throws Exception {
        try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFileName));
             BufferedOutputStream bo = new BufferedOutputStream(out);) {
            zip(out, inputFile, inputFile.getName(), bo);
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 递归压缩
     *
     * @param out
     * @param f
     * @param base
     * @param bo
     * @throws Exception
     * @author July july_sky@foxmail.com
     * @date 2017年8月24日 下午5:23:26
     */
    private static void zip(ZipOutputStream out, File f, String base, BufferedOutputStream bo) throws Exception { // 方法重载
        if (f.isDirectory()) {
            File[] files = f.listFiles();
            if (files.length == 0) {
                out.putNextEntry(new ZipEntry(base + "/")); // 创建zip压缩进入点base
                out.flush();
            }
            for (File file : files) {
                zip(out, file, base + "/" + file.getName(), bo); // 递归遍历子文件夹
            }
        } else {
            out.putNextEntry(new ZipEntry(base)); // 创建zip压缩进入点base
            out.flush();
            try (FileInputStream in = new FileInputStream(f);) {
                byte bt[] = new byte[512];
                int b = 0;
                while ((b = in.read(bt)) != -1) {
                    bo.write(bt, 0, b); // 将字节流写入当前zip目录
                }
                bo.flush();
            } catch (Exception e) {
                log.error(e.getMessage(),e);
            }
        }
    }

    public static void zip(ZipOutputStream out, InputStream input, String fileName, BufferedOutputStream bo) throws IOException {
        out.putNextEntry(new ZipEntry(fileName)); // 创建压缩文件
        out.flush();
        byte bt[] = new byte[512];
        int b = -1;
        while ((b = input.read(bt)) != -1) {
            bo.write(bt, 0, b); // 将字节流写入当前zip目录
        }
        bo.flush();
    }

    public static void zipComp(String zipFileName, File inputFile) throws Exception {
        if (inputFile.isDirectory()) {
            File[] files = inputFile.listFiles();
            try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFileName));
                 BufferedOutputStream bo = new BufferedOutputStream(out);) {
                for (File file : files) {
                    if (file.isFile()) {
                        try (InputStream in = new FileInputStream(file);) {
                            zip(out, in, file.getName(), bo);
                        } catch (Exception e) {
                            throw e;
                        }
                    }
                }
            } catch (Exception e) {
                throw e;
            }
            return;
        }
        try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFileName));
             BufferedOutputStream bo = new BufferedOutputStream(out); InputStream in = new FileInputStream(inputFile);) {
            zip(out, in, inputFile.getName(), bo);
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 文件压缩
     *
     * @param zipFileName
     * @param fileMap
     * @throws Exception
     * @author July july_sky@foxmail.com
     * @date 2017年8月25日 上午10:42:49
     */
    public static void zipComp(String zipFileName, Map<String, MultipartFile> fileMap) throws Exception {
        try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFileName));
             BufferedOutputStream bo = new BufferedOutputStream(out);) {
            for (Map.Entry<String, MultipartFile> mfile : fileMap.entrySet()) {
                if (StringUtils.isBlank(mfile) || StringUtils.isBlank(mfile.getValue()) || StringUtils.isBlank(mfile.getValue().getOriginalFilename())) {
                    continue;
                }
                zip(out, mfile.getValue().getInputStream(), mfile.getKey(), bo);
            }
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 文件压缩
     *
     * @param zipFileName 压缩文件名称
     * @param upload 文件所在路径
     * @param orgNames 要压缩的文件列表
     * @throws Exception
     * @author July july_sky@foxmail.com
     * @date 2017年9月3日 下午11:50:25
     */
    public static List<String> zipCom(String zipFileName, String upload, List<String> orgNames) throws Exception {
        List<String> zipFiles = new ArrayList<>();
        try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFileName));
             BufferedOutputStream bo = new BufferedOutputStream(out);) {
            Path path = null;
            for (String file : orgNames) {
                path = Paths.get(upload, file);
                // 如果文件不存在或文件为目录，则直接跳过
                if (Files.notExists(path) || Files.isDirectory(path)) {
                    continue;
                }
                try (InputStream input = new FileInputStream(path.toFile());) {
                    zip(out, input, path.toFile().getName(), bo);
                    zipFiles.add(file);
                } catch (Exception e) {
                    log.error(e.getMessage(),e);
                }
            }
        } catch (Exception e) {
            throw e;
        }
        return zipFiles;
    }
}